#include "Octree.h"

const char * Octree::Node::s_HLSL_STRUCT_STR = "struct Node"
		"{"
		"	uint key;"
		"	int verticesBaseIdx;"
		"	int verticesNum;"
		"	int parentIdx;"
		"	int childIdxs[8];"
		"	int neighborIdxs[27];"
		"	int nodeVertexIdxs[8];"
		"	int nodeEdgeIdxs[12];"
		"};";

const char * Octree::NodeVertex::s_HLSL_STRUCT_STR = "struct NodeVertex"
		"{"
		"	float3 loc;"
		"	int valid;"
		"	int nodeIdxs[8];"
		"};";

const char * Octree::NodeEdge::s_HLSL_STRUCT_STR = "struct NodeEdge"
		"{"
		"	int valid;"
		"	int vertexIdx;"
		"	int nodeVertexIdxs[2];"
		"	int nodeIdxs[4];"
		"};";
const char * Octree::NodeVertexValue::s_HLSL_STRUCT_STR = "struct NodeVertexValue"
	"{"
	"	float value;"
	"	float3 normal;"
	"	float3 color;"
	"};";

Octree::Octree (UINT boxSize, UINT elemNum, UINT maxLevels, UINT origVertexNum)
{
	finalNodesBufInitData.resize (elemNum * 3);
	nodeVerticesBufInitData.resize (elemNum * 8);
	nodeEdgesBufInitData.resize (elemNum * 12);
	structInfo.var.maxLevel = maxLevels;
	structInfo.var.boxSize = boxSize;
	structInfo.var.elemNum = elemNum;

	QD3DUtils d3DUtils;

	p_octreeInfoDxConstBuf = d3DUtils.createConstBuffer (&structInfo);

	ID3D11Buffer *p_verticesDxBuf = d3DUtils.createStructuredBuffer (
			origVertexNum, (Vertex*)NULL,
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS);
	p_verticesPack = new QD3DResourcePack (p_verticesDxBuf);

	ID3D11Buffer *p_nodesDxBuf = d3DUtils.createStructuredBuffer (
			finalNodesBufInitData.size (), &finalNodesBufInitData[0],
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
			"Nodes");
	p_nodesPack = new QD3DResourcePack (p_nodesDxBuf);

	ID3D11Buffer *p_nodeVerticesDxBuf = d3DUtils.createStructuredBuffer (
			nodeVerticesBufInitData.size (), &nodeVerticesBufInitData[0],
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
			"NodeVertices");
	p_nodeVerticesPack = new QD3DResourcePack (p_nodeVerticesDxBuf);

	ID3D11Buffer *p_nodeEdgesDxBuf = d3DUtils.createStructuredBuffer (
			nodeEdgesBufInitData.size (), &nodeEdgesBufInitData[0],
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
			"NodeEdges");
	p_nodeEdgesPack = new QD3DResourcePack (p_nodeEdgesDxBuf);
	ID3D11Buffer *p_nodeVerticeValuesDxBuf =
			d3DUtils.createStructuredBuffer (
			elemNum * 8, (NodeVertexValue*)NULL,
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
			"NodeVertexValues");
	p_nodeVerticeValuesPack = new QD3DResourcePack (
			p_nodeVerticeValuesDxBuf);
	ID3D11Buffer *p_levelAddrsDxBuf = d3DUtils.createStructuredBuffer (
			structInfo.var.maxLevel, (glm::ivec2 *)NULL,
			D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
			"OctreeLevels");
	p_levelPack = new QD3DResourcePack (p_levelAddrsDxBuf);

}

Octree::~Octree ()
{
	SAFE_RELEASE (p_octreeInfoDxConstBuf);
	SAFE_DELETE (p_verticesPack);
	SAFE_DELETE (p_nodesPack);
	SAFE_DELETE (p_nodeVerticesPack);
	SAFE_DELETE (p_nodeEdgesPack);
	SAFE_DELETE (p_nodeVerticeValuesPack);
	SAFE_DELETE (p_levelPack);
}

void Octree::clear ()
{
	QD3DUtils d3DUtils;
	d3DUtils.updateSubresource (p_nodesPack->getRes (), 0, &finalNodesBufInitData[0]);
	d3DUtils.updateSubresource (p_nodeVerticesPack->getRes (), 0, &nodeVerticesBufInitData[0]);
	d3DUtils.updateSubresource (p_nodeEdgesPack->getRes (), 0, &nodeEdgesBufInitData[0]);
}

